/*
Name 1: Renato Oliveira 
Name 2: David Kohtz
Name 3: Dawit Habtgiorgis
UTEID 1: rad2735
UTEID 2: dak964
UTEID 3: dh27548
*/

/***************************************************************/
/*                                                             */
/*   LC-3b Instruction Level Simulator                         */
/*                                                             */
/*   EE 460N                                                   */
/*   The University of Texas at Austin                         */
/*                                                             */
/***************************************************************/

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/***************************************************************/
/*                                                             */
/* Files: isaprogram   L                                       */
/***************************************************************/

/***************************************************************/
/* These are the functions you'll have to write.               */
/***************************************************************/

void process_instruction();

/***************************************************************/
/* A couple of useful definitions.                             */
/***************************************************************/
#define FALSE 0
#define TRUE  1

/***************************************************************/
/* Use this to avoid overflowing 16 bits on the bus.           */
/***************************************************************/
#define Low16bits(x) ((x) & 0xFFFF)

/***************************************************************/
/* Main memory.                                                */
/***************************************************************/
/* MEMORY[A][0] stores the least significant byte of word at word address A
MEMORY[A][1] stores the most significant byte of word at word address A 
*/

#define WORDS_IN_MEM    0x08000 
int MEMORY[WORDS_IN_MEM][2];

/***************************************************************/

/***************************************************************/

/***************************************************************/
/* LC-3b State info.                                           */
/***************************************************************/
#define LC_3b_REGS 8

int RUN_BIT;	/* run bit */


typedef struct System_Latches_Struct{

  int PC,	/* program counter */
    N,		/* n condition bit */
    Z,		/* z condition bit */
    P;		/* p condition bit */
  int REGS[LC_3b_REGS]; /* register file. */
} System_Latches;

/* Data Structure for Latch */

System_Latches CURRENT_LATCHES, NEXT_LATCHES;

/***************************************************************/
/* A cycle counter.                                            */
/***************************************************************/
int INSTRUCTION_COUNT;

/***************************************************************/
/*                                                             */
/* Procedure : help                                            */
/*                                                             */
/* Purpose   : Print out a list of commands                    */
/*                                                             */
/***************************************************************/
void help() {                                                    
  printf("----------------LC-3b ISIM Help-----------------------\n");
  printf("go               -  run program to completion         \n");
  printf("run n            -  execute program for n instructions\n");
  printf("mdump low high   -  dump memory from low to high      \n");
  printf("rdump            -  dump the register & bus values    \n");
  printf("?                -  display this help menu            \n");
  printf("quit             -  exit the program                  \n\n");
}

/***************************************************************/
/*                                                             */
/* Procedure : cycle                                           */
/*                                                             */
/* Purpose   : Execute a cycle                                 */
/*                                                             */
/***************************************************************/
void cycle() {                                                

  process_instruction();
  CURRENT_LATCHES = NEXT_LATCHES;
  INSTRUCTION_COUNT++;
}

/***************************************************************/
/*                                                             */
/* Procedure : run n                                           */
/*                                                             */
/* Purpose   : Simulate the LC-3b for n cycles                 */
/*                                                             */
/***************************************************************/
void run(int num_cycles) {                                      
  int i;

  if (RUN_BIT == FALSE) {
    printf("Can't simulate, Simulator is halted\n\n");
    return;
  }

  printf("Simulating for %d cycles...\n\n", num_cycles);
  for (i = 0; i < num_cycles; i++) {
    if (CURRENT_LATCHES.PC == 0x0000) {
      RUN_BIT = FALSE;
      printf("Simulator halted\n\n");
      break;
    }
    cycle();
  }
}

/***************************************************************/
/*                                                             */
/* Procedure : go                                              */
/*                                                             */
/* Purpose   : Simulate the LC-3b until HALTed                 */
/*                                                             */
/***************************************************************/
void go() {                                                     
  if (RUN_BIT == FALSE) {
    printf("Can't simulate, Simulator is halted\n\n");
    return;
  }

  printf("Simulating...\n\n");
  while (CURRENT_LATCHES.PC != 0x0000)
    cycle();
  RUN_BIT = FALSE;
  printf("Simulator halted\n\n");
}

/***************************************************************/ 
/*                                                             */
/* Procedure : mdump                                           */
/*                                                             */
/* Purpose   : Dump a word-aligned region of memory to the     */
/*             output file.                                    */
/*                                                             */
/***************************************************************/
void mdump(FILE * dumpsim_file, int start, int stop) {          
  int address; /* this is a byte address */

  printf("\nMemory content [0x%.4x..0x%.4x] :\n", start, stop);
  printf("-------------------------------------\n");
  for (address = (start >> 1); address <= (stop >> 1); address++)
    printf("  0x%.4x (%d) : 0x%.2x%.2x\n", address << 1, address << 1, MEMORY[address][1], MEMORY[address][0]);
  printf("\n");

  /* dump the memory contents into the dumpsim file */
  fprintf(dumpsim_file, "\nMemory content [0x%.4x..0x%.4x] :\n", start, stop);
  fprintf(dumpsim_file, "-------------------------------------\n");
  for (address = (start >> 1); address <= (stop >> 1); address++)
    fprintf(dumpsim_file, " 0x%.4x (%d) : 0x%.2x%.2x\n", address << 1, address << 1, MEMORY[address][1], MEMORY[address][0]);
  fprintf(dumpsim_file, "\n");
  fflush(dumpsim_file);
}

/***************************************************************/
/*                                                             */
/* Procedure : rdump                                           */
/*                                                             */
/* Purpose   : Dump current register and bus values to the     */   
/*             output file.                                    */
/*                                                             */
/***************************************************************/
void rdump(FILE * dumpsim_file) {                               
  int k; 

  printf("\nCurrent register/bus values :\n");
  printf("-------------------------------------\n");
  printf("Instruction Count : %d\n", INSTRUCTION_COUNT);
  printf("PC                : 0x%.4x\n", CURRENT_LATCHES.PC);
  printf("CCs: N = %d  Z = %d  P = %d\n", CURRENT_LATCHES.N, CURRENT_LATCHES.Z, CURRENT_LATCHES.P);
  printf("Registers:\n");
  for (k = 0; k < LC_3b_REGS; k++)
    printf("%d: 0x%.4x\n", k, CURRENT_LATCHES.REGS[k]);
  printf("\n");

  /* dump the state information into the dumpsim file */
  fprintf(dumpsim_file, "\nCurrent register/bus values :\n");
  fprintf(dumpsim_file, "-------------------------------------\n");
  fprintf(dumpsim_file, "Instruction Count : %d\n", INSTRUCTION_COUNT);
  fprintf(dumpsim_file, "PC                : 0x%.4x\n", CURRENT_LATCHES.PC);
  fprintf(dumpsim_file, "CCs: N = %d  Z = %d  P = %d\n", CURRENT_LATCHES.N, CURRENT_LATCHES.Z, CURRENT_LATCHES.P);
  fprintf(dumpsim_file, "Registers:\n");
  for (k = 0; k < LC_3b_REGS; k++)
    fprintf(dumpsim_file, "%d: 0x%.4x\n", k, CURRENT_LATCHES.REGS[k]);
  fprintf(dumpsim_file, "\n");
  fflush(dumpsim_file);
}

/***************************************************************/
/*                                                             */
/* Procedure : get_command                                     */
/*                                                             */
/* Purpose   : Read a command from standard input.             */  
/*                                                             */
/***************************************************************/
void get_command(FILE * dumpsim_file) {                         
  char buffer[20];
  int start, stop, cycles;

  printf("LC-3b-SIM> ");

  scanf("%s", buffer);
  printf("\n");

  switch(buffer[0]) {
  case 'G':
  case 'g':
    go();
    break;

  case 'M':
  case 'm':
    scanf("%i %i", &start, &stop);
    mdump(dumpsim_file, start, stop);
    break;

  case '?':
    help();
    break;
  case 'Q':
  case 'q':
    printf("Bye.\n");
    exit(0);

  case 'R':
  case 'r':
    if (buffer[1] == 'd' || buffer[1] == 'D')
      rdump(dumpsim_file);
    else {
      scanf("%d", &cycles);
      run(cycles);
    }
    break;

  default:
    printf("Invalid Command\n");
    break;
  }
}

/***************************************************************/
/*                                                             */
/* Procedure : init_memory                                     */
/*                                                             */
/* Purpose   : Zero out the memory array                       */
/*                                                             */
/***************************************************************/
void init_memory() {                                           
  int i;

  for (i=0; i < WORDS_IN_MEM; i++) {
    MEMORY[i][0] = 0;
    MEMORY[i][1] = 0;
  }
}

/**************************************************************/
/*                                                            */
/* Procedure : load_program                                   */
/*                                                            */
/* Purpose   : Load program and service routines into mem.    */
/*                                                            */
/**************************************************************/
void load_program(char *program_filename) {                   
  FILE * prog;
  int ii, word, program_base;

  /* Open program file. */
  prog = fopen(program_filename, "r");
  if (prog == NULL) {
    printf("Error: Can't open program file %s\n", program_filename);
    exit(-1);
  }

  /* Read in the program. */
  if (fscanf(prog, "%x\n", &word) != EOF)
    program_base = word >> 1;
  else {
    printf("Error: Program file is empty\n");
    exit(-1);
  }

  ii = 0;
  while (fscanf(prog, "%x\n", &word) != EOF) {
    /* Make sure it fits. */
    if (program_base + ii >= WORDS_IN_MEM) {
      printf("Error: Program file %s is too long to fit in memory. %x\n",
        program_filename, ii);
      exit(-1);
    }

    /* Write the word to memory array. */
    MEMORY[program_base + ii][0] = word & 0x00FF;
    MEMORY[program_base + ii][1] = (word >> 8) & 0x00FF;
    ii++;
  }

  if (CURRENT_LATCHES.PC == 0) CURRENT_LATCHES.PC = (program_base << 1);

  printf("Read %d words from program into memory.\n\n", ii);
}

/************************************************************/
/*                                                          */
/* Procedure : initialize                                   */
/*                                                          */
/* Purpose   : Load machine language program                */ 
/*             and set up initial state of the machine.     */
/*                                                          */
/************************************************************/
void initialize(char *program_filename, int num_prog_files) { 
  int i;

  init_memory();
  for ( i = 0; i < num_prog_files; i++ ) {
    load_program(program_filename);
    while(*program_filename++ != '\0');
  }
  CURRENT_LATCHES.Z = 1;  
  NEXT_LATCHES = CURRENT_LATCHES;

  RUN_BIT = TRUE;
}

/***************************************************************/
/*                                                             */
/* Procedure : main                                            */
/*                                                             */
/***************************************************************/
int main(int argc, char *argv[]) {                              
  FILE * dumpsim_file;

  /* Error Checking */
  if (argc < 2) {
    printf("Error: usage: %s <program_file_1> <program_file_2> ...\n",
      argv[0]);
    exit(1);
  }

  printf("LC-3b Simulator\n\n");

  initialize(argv[1], argc - 1);

  if ( (dumpsim_file = fopen( "dumpsim", "w" )) == NULL ) {
    printf("Error: Can't open dumpsim file\n");
    exit(-1);
  }

  while (1)
    get_command(dumpsim_file);

}

/***************************************************************/
/* Do not modify the above code.
You are allowed to use the following global variables in your
code. These are defined above.

MEMORY

CURRENT_LATCHES
NEXT_LATCHES

You may define your own local/global variables and functions.
You may use the functions to get at the control bits defined
above.

Begin your code here 	  			       */

/***************************************************************/


/*
* Takes the CURRENT_LATCHES.PC and uses that to pull the next instruction from the 
* MEMORY[][]. This takes care of the byte ordering and places them into one int value
*/
unsigned short fetchInstruction(void)
{
  /*Variables*/
  unsigned short instruction = 0;
  /*Code*/
  instruction = ((MEMORY[(CURRENT_LATCHES.PC)>>1][1] & 0x00FF) << 8) | (MEMORY[(CURRENT_LATCHES.PC)>>1][0] & 0x00FF);
  return instruction;
}

/*
* Takes the full word instruction and returns the opcode number
* in the lowest bits (i.e. Just the opcode itself is returned)
*/
unsigned short decodeOpCode(unsigned short hexCode)
{
  /*Variables*/
  unsigned short temp = 0;
  /*Code*/
  temp = ((hexCode & 0xF000) >> 12);
  return temp;
}

void setCC(signed short answer)
{
  NEXT_LATCHES.Z=0;
  NEXT_LATCHES.N=0;
  NEXT_LATCHES.P=0;

  if(answer == 0)
  {
    NEXT_LATCHES.Z = TRUE;
  }
  else if(answer < 0)
  {
    NEXT_LATCHES.N = TRUE;
  }
  else
  {
    NEXT_LATCHES.P = TRUE;
  }
}

void incrementPC(void)
{
  NEXT_LATCHES.PC = CURRENT_LATCHES.PC + 2;
}

void add(unsigned short instruction)
{
  /*Variables*/
  unsigned short destReg = 0;
  unsigned short sourceReg1 = 0;
  unsigned short sourceReg2 = 0;
  short immediate = 0;
  short answer = 0;

  /*Code*/
  destReg = ((instruction & 0x0E00) >> 9);
  sourceReg1 = ((instruction & 0x01C0) >> 6);
  /* Check bit 5, if one then use immediate feild
  * else use sourceReg2
  */
  if((instruction & 0x0020) == 0x0020)
  {
    /*check negative or positive*/
    if((instruction & 0x0010) == 0x0010)
    {
      /*Negative number needs sign extension*/
      immediate = (0xFFF0 | (instruction & 0x000F));
    }
    else
    {
      /*Positive number doesn't need sign extension*/
      immediate = (instruction & 0x000F);
    }
    answer = CURRENT_LATCHES.REGS[sourceReg1] + (int)immediate;
    /*Update the next latch registers*/
    NEXT_LATCHES.REGS[destReg] = ((int)answer & 0x0000FFFF);
    setCC(answer);
    incrementPC();
  }
  else
  {
    sourceReg2 = (instruction & 0x0007);
    answer = CURRENT_LATCHES.REGS[sourceReg1] + CURRENT_LATCHES.REGS[sourceReg2];
    /*Update the next latch registers*/
    NEXT_LATCHES.REGS[destReg] = ((int)answer & 0x0000FFFF);
    setCC(answer);
    incrementPC();
  }
}

void and(unsigned short instruction)
{
  /*Variables*/
  unsigned short destReg = 0;
  unsigned short sourceReg1 = 0;
  unsigned short sourceReg2 = 0;
  short immediate = 0;
  short answer = 0;

  /*Code*/
  destReg = ((instruction & 0x0E00) >> 9);
  sourceReg1 = ((instruction & 0x01C0) >> 6);
  /* Check bit 5, if one then use immediate feild
  * else use sourceReg2
  */
  if((instruction & 0x0020) == 0x0020)
  {
    /*check negative or positive*/
    if((instruction & 0x0010) == 0x0010)
    {
      /*Negative number needs sign extension*/
      immediate = (0xFFF0 | (instruction & 0x000F));
    }
    else
    {
      /*Positive number doesn't need sign extension*/
      immediate = (instruction & 0x000F);
    }
    answer = CURRENT_LATCHES.REGS[sourceReg1] & (int)immediate;
    /*Update the next latch registers*/
    NEXT_LATCHES.REGS[destReg] = ((int)answer & 0x0000FFFF);
    setCC(answer);
    incrementPC();
  }
  else
  {
    sourceReg2 = (instruction & 0x0007);
    answer = CURRENT_LATCHES.REGS[sourceReg1] & CURRENT_LATCHES.REGS[sourceReg2];
    /*Update the next latch registers*/
    NEXT_LATCHES.REGS[destReg] = ((int)answer & 0x0000FFFF);
    setCC(answer);
    incrementPC();
  }
}

void br(unsigned short instruction)
{
  /*Variables*/

  unsigned short n,z,p;
  signed short imm9 = 0;
  int destReg = 0;
  /*Code*/

  /*get the condition codes from the instrucion*/
  n = z = p = 0;
  n = instruction>>11 & 0x0001;
  z = instruction>>10 & 0x0001;
  p = instruction>>9 & 0x0001;

  /*get the immediate number and check for pos or neg*/
  imm9 = 0x01FF&instruction;
  if(imm9&0x0100)
    imm9 |= 0xFE00;

  /*check what are the condition code*/
  if((n&CURRENT_LATCHES.N)|(z&CURRENT_LATCHES.Z)|(p&CURRENT_LATCHES.P))
  {
    /*set the next PC to point to the branch target*/
    NEXT_LATCHES.PC = (CURRENT_LATCHES.PC+2) + (imm9 *2);
  }
  else if(n == 0 && z == 0 && p == 0)
  {
    /*set the next PC to point to the branch target as BR is an unconditional branch*/
    NEXT_LATCHES.PC = (CURRENT_LATCHES.PC+2) + (imm9 *2);
  }
  else if(n == 1 && z == 1 && p == 1)
  {
    /*set the next PC to point to the branch target as BR is an unconditional branch*/
    NEXT_LATCHES.PC = (CURRENT_LATCHES.PC+2) + (imm9 *2);
  }
  else 
  {incrementPC();}/*if you are not taking the br incrementPC*/
}

void jmp(unsigned short instruction)
{
  /*Variables*/
  unsigned short BaseReg = 0;

  /*Code*/
  /*get the base register*/
  BaseReg = (instruction>>6) & 0x07;

  /*set the Next PC to the baseReg contents*/
  NEXT_LATCHES.PC = CURRENT_LATCHES.REGS[BaseReg];
}

void jsr(unsigned short instruction)
{
  /*Variables*/
  unsigned short baseReg = 0;
  short immediate = 0;
  /*Code*/
  /*set register 7 to the PC+2, both versions just in case they try this*/
  NEXT_LATCHES.REGS[7] = CURRENT_LATCHES.PC + 2;
  CURRENT_LATCHES.REGS[7] = CURRENT_LATCHES.PC + 2;
  /*if bit 11 is 1, it is JSR*/
  if((instruction & 0x0800) == 0x0800)
  {
    /*compute PC offset*/
    if((instruction & 0x0400) == 0x0400)
    {
      immediate = ( 0xFC00 | (instruction & 0x03FF));
    }
    else
    {
      immediate = (instruction & 0x03FF); 
    }
    NEXT_LATCHES.PC = (CURRENT_LATCHES.PC + 2) + immediate*2;
  }

  /*else it is  JSSR*/
  else
  {
    baseReg = ((instruction & 0x01C0) >> 6);
    NEXT_LATCHES.PC = CURRENT_LATCHES.REGS[baseReg];
  }
}

void ldb(unsigned short instruction)
{
  /*Variables*/
  signed   int   BaseRegCont = 0;
  signed   int   locationOffest = 0;
  unsigned short Dr = 0;
  unsigned short BaseReg = 0;
  signed   short imm6 = 0;
  unsigned short hiLow = 0;


  /*Code*/

  /*get the operands*/
  Dr      = (instruction>>9) & 0x07;
  BaseReg = (instruction>>6) & 0x07;
  imm6    = (instruction) & 0x3F;

  /*get the contents of the Base Register*/
  BaseRegCont = CURRENT_LATCHES.REGS[BaseReg];

  /*sing extend imm6*/
  if (imm6 & 0x0020)
  {
    imm6 |= 0xFFC0;
  }

  /*add the base contents with the 6 bit offset (THIS OFFSET DOESN"T GET MULTIPLIED SINCE IT IS BYTE ADDRESSING)*/
  locationOffest = (BaseRegCont + imm6) & 0x0000FFFF;

  if (locationOffest % 2 == 1)
  {
    /*This is an odd memory location, odd locations always hold the top byte in memory*/
    hiLow = 1;
  }
  else
  {
    /*This is an even memory location, even locations always hold the bottom byte*/
    hiLow = 0;
  }
  /*set the Destination register "DR" with the contents of the Base Register + offset*/
  NEXT_LATCHES.REGS[Dr] = MEMORY[locationOffest / 2][hiLow] & 0x00FF;

  /*sign extend the low byte*/
  if(NEXT_LATCHES.REGS[Dr]&0x0080)
  {NEXT_LATCHES.REGS[Dr] |= 0xFFFFFF00;}

  setCC((signed short)NEXT_LATCHES.REGS[Dr]);
  incrementPC();

}

void ldw(unsigned short instruction)
{
  /*Variables*/
  signed   int    BaseRegCont = 0;
  signed   int    locationOffest = 0;
  unsigned short  Dr = 0;
  unsigned short  BaseReg = 0;
  signed   short  imm6 = 0;

  /*Code*/
  /*get the operands*/
  Dr      = (instruction>>9) & 0x07;
  BaseReg = (instruction>>6) & 0x07;
  imm6    = instruction & 0x3F;

  /*get the contents of the Base Register*/
  BaseRegCont = CURRENT_LATCHES.REGS[BaseReg];

  /*sing extend imm6*/
  if(imm6&0x0020) 
  {imm6 |= 0xFFC0;}

  /*add the base contents with the 6 bit offset*/
  locationOffest = BaseRegCont + imm6*2;

  /*set the Destination register "DR" with the contents of the Base Register + offset*/
  NEXT_LATCHES.REGS[Dr] = ((MEMORY[locationOffest/2][1] & 0x00FF) << 8) | (MEMORY[locationOffest/2][0] & 0x00FF);

  if(NEXT_LATCHES.REGS[Dr]& 0x00008000) /*sign extend the int (just in case)*/
  {NEXT_LATCHES.REGS[Dr] = NEXT_LATCHES.REGS[Dr] | 0xFFFF0000;}

  setCC((signed short)NEXT_LATCHES.REGS[Dr]);
  incrementPC();
}

void lea(unsigned short instruction)
{
  /*Variables*/
  unsigned short	destReg = 0;
  short			immediate = 0;
  /*Code*/
  destReg = ((instruction & 0x0E00) >> 9);
  /*Check sign and extend if needed*/
  if((instruction & 0x0100) == 0x0100)
  {
    immediate = (0xFF00 | (instruction & 0x00FF));
  }
  else
  {
    immediate = (instruction & 0x00FF);
  }
  NEXT_LATCHES.REGS[destReg] = (CURRENT_LATCHES.PC + 2) + immediate*2;
  /*WE DON'T SET CONDITION CODDES ON LEA*/
  incrementPC();
}

/*
void rti(unsigned short instruction)
{

}
*/

void shf(unsigned short instruction)
{
  /*Variables*/
  unsigned short destReg = 0;
  unsigned short sourceReg1 = 0;
  short immediate = 0;
  /*Code*/
  destReg = ((instruction & 0x0E00) >> 9);
  sourceReg1 = ((instruction & 0x01C0) >> 6);
  immediate  =(instruction & 0x000F);/* you need this here*/

  if((instruction & 0x0030) == 0x0000)
  {
    /*Left Shift*/
    NEXT_LATCHES.REGS[destReg] = CURRENT_LATCHES.REGS[sourceReg1] << immediate;
  }
  else if((instruction & 0x0030) == 0x0010)
  {
    /*Logical Right Shift*/
    NEXT_LATCHES.REGS[destReg] = (unsigned int)CURRENT_LATCHES.REGS[sourceReg1] >> (unsigned short)(immediate & 0x000F);
  }
  else if((instruction & 0x0030) == 0x0030)
  {
    /*Arithmetic Right Shift*/
    NEXT_LATCHES.REGS[destReg] = CURRENT_LATCHES.REGS[sourceReg1] >> immediate ;
  }
  else
  {
    /*Error*/
  }
  setCC((signed short)NEXT_LATCHES.REGS[destReg]);
  incrementPC();
}

void stb(unsigned short instruction)
{
  /*Variables*/
  signed   int  BaseRegCont = 0;
  signed   int  locationOffest = 0;
  unsigned short Sr = 0;
  unsigned short BaseReg = 0;
  signed   short imm6 = 0;
  unsigned short hiLow = 0;

  /*Code*/

  /*get the operands*/
  Sr = (instruction >> 9) & 0x07;
  BaseReg = (instruction >> 6) & 0x07;
  imm6 = (instruction)& 0x3F;

  /*get the contents of the Base Register*/
  BaseRegCont = CURRENT_LATCHES.REGS[BaseReg];

  /*sing extend imm6*/
  if (imm6 & 0x0020) imm6 |= 0xFFC0;

  /*add the base contents with the 6 bit offset (THIS OFFSET DOESN"T GET MULTIPLIED SINCE IT IS BYTE ADDRESSING)*/
  locationOffest = BaseRegCont + imm6;

  if (locationOffest % 2 == 1)
  {
    /*This is an odd memory location, odd locations always hold the top byte in memory*/
    hiLow = 1;
  }
  else
  {
    /*This is an even memory location, even locations always hold the bottom byte*/
    hiLow = 0;
  }

  /*set the Memory with the contents of Source register "Sr"*/
  MEMORY[(locationOffest / 2)][hiLow] = 0x00FF & CURRENT_LATCHES.REGS[Sr];

  incrementPC();
}

void stw(unsigned short instruction)
{
  /*Variables*/
  signed         BaseRegCont = 0;
  signed         locationOffest;
  unsigned short Sr = 0;
  unsigned short BaseReg = 0;
  char           imm6 = 0;

  /*Code*/

  /*get the operands*/
  Sr      = (instruction>>9) & 0x07;
  BaseReg = (instruction>>6) & 0x07;
  imm6    = (instruction) & 0x3F;

  /*get the contents of the Base Register*/
  BaseRegCont = CURRENT_LATCHES.REGS[BaseReg];

  /*sing extend imm6*/
  if(imm6&0x0020) imm6 |= 0xFFC0;

  /*add the base contents with the 6 bit offset*/
  locationOffest = BaseRegCont + imm6*2;

  /*set the Memory with the contents of Source register "Sr"*/
  MEMORY[locationOffest/2][0] = 0x00FF & CURRENT_LATCHES.REGS[Sr];
  MEMORY[locationOffest/2][1] = 0x00FF & (CURRENT_LATCHES.REGS[Sr] >> 8);

  incrementPC();
}

void trap(unsigned short instruction)
{
  /*Variables*/
  unsigned char vector = 0;
  /*Code*/
  /*get the trap vector*/
  vector = instruction & 0x00FF;

  /*store the current PC into R7*/
  NEXT_LATCHES.REGS[7] = (CURRENT_LATCHES.PC+2);
  NEXT_LATCHES.PC = (MEMORY[(vector)][1] << 8) | (MEMORY[(vector)][0]);
}

void xor(unsigned short instruction)
{
  /*Variables*/
  unsigned short destReg = 0;
  unsigned short sourceReg1 = 0;
  unsigned short sourceReg2 = 0;
  short immediate = 0;
  short answer = 0;

  /*Code*/
  destReg = ((instruction & 0x0E00) >> 9);
  sourceReg1 = ((instruction & 0x01C0) >> 6);
  /* Check bit 5, if one then use immediate feild
  * else use sourceReg2
  */
  if((instruction & 0x0020) == 0x0020)
  {
    /*check negative or positive*/
    if((instruction & 0x0010) == 0x0010)
    {
      /*Negative number needs sign extension*/
      immediate = (0xFFF0 | (instruction & 0x000F));
    }
    else
    {
      /*Positive number doesn't need sign extension*/
      immediate = (instruction & 0x000F);
    }
    answer = CURRENT_LATCHES.REGS[sourceReg1] ^ (int)immediate;
    /*Update the next latch registers*/
    NEXT_LATCHES.REGS[destReg] = ((int)answer & 0x0000FFFF);
    setCC(answer);
    incrementPC();
  }
  else
  {
    sourceReg2 = (instruction & 0x0007);
    answer = CURRENT_LATCHES.REGS[sourceReg1] ^ CURRENT_LATCHES.REGS[sourceReg2];
    /*Update the next latch registers*/
    NEXT_LATCHES.REGS[destReg] = ((int)answer & 0x0000FFFF);
    setCC(answer);
    incrementPC();
  }
}

/*  function: process_instruction
*  
*    Process one instruction at a time  
*       -Fetch one instruction
*       -Decode
*       -switch in here
*       -Execute
*       -Update NEXT_LATCHES
*/     
void process_instruction(){
  unsigned short inst;

  /*fetch the instruction in the current memory location*/
  inst = fetchInstruction();

  /*check what instrucion is*/
  switch(decodeOpCode(inst)) {
  case 0: /*BR*/
    {
      br(inst);
      break;
    }
  case 1: /*ADD*/
    {
      add(inst);
      break;
    }
  case 2: /*LDB*/
    {
      ldb(inst);
      break;
    }
  case 3: /*STB*/
    {
      stb(inst);
      break;
    }
  case 4: /*JSR/JSRR*/
    {
      jsr(inst);
      break;
    }
  case 5: /*AND*/
    {
      and(inst);
      break;
    }
  case 6: /*LDW*/
    {
      ldw(inst);
      break;
    }
  case 7: /*STW*/
    {
      stw(inst);
      break;
    }
  case 8: /*RTI*/
    {
      break;
    }
  case 9: /*XOR*/
    {
      xor(inst);
      break;
    }
  case 10: /*not used*/
    {
      break;
    }
  case 11: /*not used*/
    {
      break;
    }
  case 12: /*JMP/RET*/
    {
      jmp(inst);
      break;
    }
  case 13: /*SHF*/
    {
      shf(inst);
      break;
    }
  case 14: /*LEA*/
    {
      lea(inst);
      break;
    }
  case 15: /*TRAP*/
    {
      trap(inst);
      break;
    }
  default:
    {
      printf("Error : invalid opcode %d\n", decodeOpCode(inst));
      break;
    }

  }
}
